package com.example.filter;

import org.apache.dubbo.common.constants.CommonConstants;
import org.apache.dubbo.common.extension.Activate;
import org.apache.dubbo.rpc.Filter;
import org.apache.dubbo.rpc.Invocation;
import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.Result;
import org.apache.dubbo.rpc.RpcException;

import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author lbq
 * @version 1.0
 * @date 2021/3/1 21:34
 */
@Activate(group = {CommonConstants.CONSUMER})
public class TPMonitorFilter implements Filter {

    private static AtomicInteger count1 = new AtomicInteger(0);
    private static AtomicInteger count2 = new AtomicInteger(0);
    private static AtomicInteger count3 = new AtomicInteger(0);
    private static int indexA = 0;
    private static int indexB = 0;
    private static int indexC = 0;
    private static long startTime = System.currentTimeMillis();
    private static ArrayList<Long> list_a = new ArrayList<>(4096);
    private static ArrayList<Long> list_b = new ArrayList<>(4096);
    private static ArrayList<Long> list_c = new ArrayList<>(4096);

    @Override
    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
        String methodName = invocation.getMethodName();
        long start = Instant.now().toEpochMilli();
        try {
            return invoker.invoke(invocation);
        } finally {
            long end = Instant.now().toEpochMilli();
            long consume = end - start;
            try {
                if (methodName.endsWith("A")) {
                    list_a.add(consume);
                    count1.incrementAndGet();
                } else if (methodName.endsWith("B")) {
                    list_b.add(consume);
                    count2.incrementAndGet();
                } else if (methodName.endsWith("C")) {
                    list_c.add(consume);
                    count3.incrementAndGet();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 计算最近一分钟内的TP90、TP99
     */
    public static void calculate() {
        List<Long> list1;
        List<Long> list2;
        List<Long> list3;
        if (System.currentTimeMillis() - startTime < 60000) {
            list1 = new ArrayList<>(list_a);
            list2 = new ArrayList<>(list_b);
            list3 = new ArrayList<>(list_c);
        } else {
            startTime = System.currentTimeMillis();
            indexA = count1.get();
            indexB = count2.get();
            indexC = count3.get();
            list1 = new ArrayList<>(list_a.subList(indexA, list_a.size()));
            list2 = new ArrayList<>(list_b.subList(indexB, list_b.size()));
            list3 = new ArrayList<>(list_c.subList(indexC, list_c.size()));
        }
        list1.sort(Long::compareTo);
        list2.sort(Long::compareTo);
        list3.sort(Long::compareTo);
        double ceila1 = Math.ceil(list1.size() * 0.9);
        double ceila2 = Math.ceil(list1.size() * 0.99);
        int ia1 = (int) ceila1;
        int ia2 = (int) ceila2;
        System.out.println("方法A的TP90: " + list1.get(ia1) + " , 方法A的TP99: " + list1.get(ia2));
        double ceilb1 = Math.ceil(list2.size() * 0.9);
        double ceilb2 = Math.ceil(list2.size() * 0.99);
        int ib1 = (int) ceilb1;
        int ib2 = (int) ceilb2;
        System.out.println("方法B的TP90: " + list2.get(ib1) + " , 方法B的TP99: " + list2.get(ib2));
        double ceilc1 = Math.ceil(list3.size() * 0.9);
        double ceilc2 = Math.ceil(list3.size() * 0.99);
        int ic1 = (int) ceilc1;
        int ic2 = (int) ceilc2;
        System.out.println("方法C的TP90: " + list3.get(ic1) + " , 方法C的TP99: " + list3.get(ic2));
    }
}
